import json
from enum import IntEnum
from Devices.Andlink.DeviceAndlink import DeviceAndlink

class AndlinkParser(object):
    class OtaType(IntEnum):
        NextRestart = 0
        Immediately = 1

    def SetDeviceID(self, deviceID):
        self.__DeviceID = deviceID

    def ParseFullStatus(data, fullStatus):
        doc = json.loads(data)
        if doc is None:
            return False

        ret, StringValue = AndlinkParser._GetStrProperty(doc, "device_id")
        if ret:
            fullStatus.deviceId = StringValue

        ret, StringValue = AndlinkParser._GetStrProperty(doc, "device_mac")
        if ret:
            fullStatus.deviceMac = StringValue

        ret, StringValue = AndlinkParser._GetStrProperty(doc, "device_type")
        if ret:
            fullStatus.deviceType = StringValue

        ret, StringValue = AndlinkParser._GetStrProperty(doc, "device_token")
        if ret:
            fullStatus.deviceToken = StringValue

        ret, StringValue = AndlinkParser._GetStrProperty(doc, "product_token")
        if ret:
            fullStatus.productToken = StringValue

        ret, StringValue = AndlinkParser._GetStrProperty(doc, "andlink_token")
        if ret:
            fullStatus.andlinkToken = StringValue

        ret, StringValue = AndlinkParser._GetStrProperty(doc, "firmware_version")
        if ret:
            fullStatus.firmwareVersion = StringValue

        ret, StringValue = AndlinkParser._GetStrProperty(doc, "software_version")
        if ret:
            fullStatus.softwareVersion = StringValue

        ret, StringValue = AndlinkParser._GetStrProperty(doc, "ip_address")
        if ret:
            fullStatus.ipAddress = StringValue

        ret, StringValue = AndlinkParser._GetStrProperty(doc, "protocolVersion")
        if ret:
            fullStatus.protocolVersion = StringValue

        AndlinkParser.__GetDeviceExtInfo(doc, fullStatus.deviceExtInfo)

        ret, intValue = AndlinkParser._GetStrProperty(doc, "heart_beat_time")
        if ret:
            fullStatus.homeGwHeartBeatTime = intValue

        ret, intValue = AndlinkParser._GetStrProperty(doc, "home_gw_heart_beat_time")
        if ret:
            fullStatus.homeGwHeartBeatTime = intValue

        ret, intValue = AndlinkParser._GetStrProperty(doc, "encrypt")
        if ret:
            fullStatus.homeGwEncrypt = intValue

        ret, intValue = AndlinkParser._GetStrProperty(doc, "home_gw_encrypt")
        if ret:
            fullStatus.homeGwEncrypt = intValue

        ret, intValue = AndlinkParser._GetIntProperty(doc, "cur_online_status")
        if ret:
            fullStatus.curOnlineStatus = intValue

        ret, intValue = AndlinkParser._GetIntProperty(doc, "bind_status")
        if ret:
            fullStatus.bindStatus = intValue

        ret, intValue = AndlinkParser._GetIntProperty(doc, "bootstrap_status")
        if ret:
            fullStatus.bootstrapStatus = intValue

        ret, intValue = AndlinkParser._GetIntProperty(doc, "boot_status")
        if ret:
            fullStatus.bootStatus = intValue

        ret, intValue = AndlinkParser._GetIntProperty(doc, "offline_status")
        if ret:
            fullStatus.offlineStatus = intValue

        ret, intValue = AndlinkParser._GetIntProperty(doc, "bootstrap_last_fail_time")
        if ret:
            fullStatus.bootstrapLastFailTime = intValue

        ret, intValue = AndlinkParser._GetIntProperty(doc, "bootstrap_fail_wait_time")
        if ret:
            fullStatus.bootstrapFailWaitTime = intValue

        ret, intValue = AndlinkParser._GetIntProperty(doc, "boot_last_fail_time")
        if ret:
            fullStatus.bootLastFailTime = intValue

        ret, intValue = AndlinkParser._GetIntProperty(doc, "boot_fail_wait_time")
        if ret:
            fullStatus.bootFailWaitTime = intValue

        ret, timeValue = AndlinkParser._GetIntProperty(doc, "boot_last_success_time")
        if ret:
            fullStatus.bootLastSuccessTime = timeValue

        ret, timeValue = AndlinkParser._GetIntProperty(doc, "last_dm_report_time")
        if ret:
            fullStatus.lastDmReportTime = timeValue

        ret, timeValue = AndlinkParser._GetIntProperty(doc, "last_check_upgrade_time")
        if ret:
            fullStatus.lastCheckUpgradeTime = timeValue

        ret, StringValue = AndlinkParser._GetStrProperty(doc, "inner_info")
        if ret:
            fullStatus.innerInfo = StringValue

        return True

    def ParseSelfdetect(data, selfdetectInfo):
        doc = json.loads(data)
        if doc is None:
            return False

        if not "data" in doc:
            return False

        dataObj = doc["data"]

        ret, intValue = AndlinkParser._GetIntProperty(dataObj, "cpuRate")
        if ret:
            selfdetectInfo.cpuRate = intValue

        ret, intValue = AndlinkParser._GetIntProperty(dataObj, "ramRate")
        if ret:
            selfdetectInfo.ramRate = intValue

        ret, stringValue = AndlinkParser._GetStrProperty(dataObj, "upLinkType")
        if ret:
            selfdetectInfo.upLinkType = stringValue

        ret, intValue = AndlinkParser._GetIntProperty(dataObj, "andlinkStatus")
        if ret:
            selfdetectInfo.andlinkStatus = intValue

        ret, intValue = AndlinkParser._GetIntProperty(dataObj, "lastUpTime")
        if ret:
            selfdetectInfo.lastUpTime = intValue

        ret, intValue = AndlinkParser._GetIntProperty(dataObj, "lastConnTime")
        if ret:
            selfdetectInfo.lastConnTime = intValue

        return True

    def ParseEvent(data):
        doc = json.loads(data)
        if doc is None:
            return (False, None, None)

        if not "eventType" in doc:
            return (False, None, None)

        eventType = doc["eventType"]

        if not "data" in doc:
            return (False, None, None)

        dataObj = doc["data"]
        return (True, eventType, dataObj)

    def _GetStrProperty(doc, attrName):
        if not attrName in doc:
            return (False, None)

        return (True, doc[attrName])

    def _GetIntProperty(doc, attrName):
        if not attrName in doc:
            return (False, None)

        return (True, doc[attrName])

    def __GetDeviceExtInfo(doc, deviceExtInfo):
        if not "deviceExtInfo" in doc:
            return False

        deviceExtinfoObj = doc["deviceExtInfo"]

        ret, StringValue = AndlinkParser._GetStrProperty(deviceExtinfoObj, "cmei")
        if ret:
            deviceExtInfo.cmei = StringValue

        ret, intValue = AndlinkParser._GetIntProperty(deviceExtinfoObj, "authMode")
        if ret:
            deviceExtInfo.authMode = intValue

        ret, StringValue = AndlinkParser._GetStrProperty(deviceExtinfoObj, "authId")
        if ret:
            deviceExtInfo.authId = StringValue

        ret, StringValue = AndlinkParser._GetStrProperty(deviceExtinfoObj, "sn")
        if ret:
            deviceExtInfo.sn = StringValue

        ret, StringValue = AndlinkParser._GetStrProperty(deviceExtinfoObj, "reserve")
        if ret:
            deviceExtInfo.reserve = StringValue

        ret, StringValue = AndlinkParser._GetStrProperty(deviceExtinfoObj, "manuDate")
        if ret:
            deviceExtInfo.manuDate = StringValue

        ret, StringValue = AndlinkParser._GetStrProperty(deviceExtinfoObj, "OS")
        if ret:
            deviceExtInfo.OS = StringValue

        AndlinkParser.__GetChipsInfo(deviceExtinfoObj, deviceExtInfo.chips)

        ret, StringValue = AndlinkParser._GetStrProperty(deviceExtinfoObj, "cpuModel")
        if ret:
            deviceExtInfo.cpuModel = StringValue

        ret, StringValue = AndlinkParser._GetStrProperty(
            deviceExtinfoObj, "romStorageSize"
        )
        if ret:
            deviceExtInfo.romStorageSize = StringValue

        ret, StringValue = AndlinkParser._GetStrProperty(
            deviceExtinfoObj, "ramStorageSize"
        )
        if ret:
            deviceExtInfo.ramStorageSize = StringValue

        ret, StringValue = AndlinkParser._GetStrProperty(
            deviceExtinfoObj, "networkType"
        )
        if ret:
            deviceExtInfo.networkType = StringValue

        ret, StringValue = AndlinkParser._GetStrProperty(
            deviceExtinfoObj, "locationInfo"
        )
        if ret:
            deviceExtInfo.locationInfo = StringValue

        ret, StringValue = AndlinkParser._GetStrProperty(
            deviceExtinfoObj, "deviceVendor"
        )
        if ret:
            deviceExtInfo.deviceVendor = StringValue

        ret, StringValue = AndlinkParser._GetStrProperty(
            deviceExtinfoObj, "deviceBrand"
        )
        if ret:
            deviceExtInfo.deviceBrand = StringValue

        ret, StringValue = AndlinkParser._GetStrProperty(
            deviceExtinfoObj, "deviceModel"
        )
        if ret:
            deviceExtInfo.deviceModel = StringValue

        ret, StringValue = AndlinkParser._GetStrProperty(deviceExtinfoObj, "wlanMac")
        if ret:
            deviceExtInfo.wlanMac = StringValue

        ret, StringValue = AndlinkParser._GetStrProperty(
            deviceExtinfoObj, "bluetoothMacAddress"
        )
        if ret:
            deviceExtInfo.bluetoothMacAddress = StringValue

        ret, StringValue = AndlinkParser._GetStrProperty(
            deviceExtinfoObj, "powerSupplyMode"
        )
        if ret:
            deviceExtInfo.powerSupplyMode = StringValue

        ret, StringValue = AndlinkParser._GetStrProperty(deviceExtinfoObj, "wifiRssi")
        if ret:
            deviceExtInfo.wifiRssi = StringValue

        ret, StringValue = AndlinkParser._GetStrProperty(deviceExtinfoObj, "deviceIP")
        if ret:
            deviceExtInfo.deviceIP = StringValue

        if "deviceManageExtInfo" in deviceExtinfoObj:
            deviceExtInfo.deviceManageExtInfo = deviceExtinfoObj["deviceManageExtInfo"]

        return True

    def __GetChipsInfo(doc, chipsInfo):
        if not "chips" in doc:
            return False

        chipsInfo.clear()
        chipsObj = doc["chips"]
        for i in range(len(chipsObj)):
            chipObj = chipsObj[i]
            chipInfo = DeviceAndlink.ChipInfo()

            ret, StringValue = AndlinkParser._GetStrProperty(chipObj, "type")
            if ret:
                chipInfo.type = StringValue
            else:
                return False

            ret, StringValue = AndlinkParser._GetStrProperty(chipObj, "factory")
            if ret:
                chipInfo.factory = StringValue
            else:
                return False

            ret, StringValue = AndlinkParser._GetStrProperty(chipObj, "model")
            if ret:
                chipInfo.model = StringValue
            else:
                return False

            chipsInfo.append(chipInfo)

        return True

    def __PackBase(self, function, deviceType=""):
        doc = {}
        doc["deviceId"] = self.__DeviceID
        doc["deviceType"] = deviceType

        if len(function) > 0:
            doc["function"] = function
        return doc

    def PackEmpty(self, function):
        doc = self.__PackBase(function)
        return json.dumps(doc, separators=(',', ':'))

    def PackNetinfo(self, ssid, password):
        doc = {}
        doc["SSID"] = ssid
        doc["password"] = password
        doc["encrypt"] = "MIXED-WPAPSK2"
        doc["channel"] = 0

        CGW = {}
        CGW["user_key"] = ""

        doc["CGW"] = CGW

        return json.dumps(doc, separators=(',', ':'))

    def PackOpenLog(self, loglvl, logTime, logUrl):
        doc = self.__PackBase("Log")
        data = {}
        data["logLevel"] = loglvl
        data["logTime"] = logTime
        data["fileUrl"] = logUrl
        data["fileType"] = "LOG"

        doc["data"] = data

        return json.dumps(doc, separators=(',', ':'))

    def PackUploadLog(self, logUrl):
        doc = self.__PackBase("Log")
        data = {}
        data["fileMode"] = "UP"
        data["fileType"] = "LOG"
        data["fileUrl"] = logUrl

        doc["data"] = data

        return json.dumps(doc, separators=(',', ':'))

    def PackFileDownload(self, url, otaType):
        doc = self.__PackBase("File")
        data = {}
        data["fileMode"] = "DOWN"
        data["fileType"] = "FIRM"
        data["fileUrl"] = url
        data["downMode"] = otaType

        doc["data"] = data

        return json.dumps(doc, separators=(',', ':'))

    def PackOTA(self, url, deviceType):
        doc = self.__PackBase("OTA", deviceType)
        data = {}
        data["versionType"] = "firmware"
        data["downloadUrl"] = url

        doc["data"] = data

        return json.dumps(doc, separators=(',', ':'))

    def PackInnerCommand(command):
        doc = {}
        doc["command"] = command
        return json.dumps(doc, separators=(',', ':'))
